package socket

import (
	"context"
	gorillaWs "github.com/gorilla/websocket"
	"github.com/kataras/iris/v12/websocket"
	"github.com/kataras/neffos"
	"github.com/kataras/neffos/gorilla"
	streamCtx "gluenet/internal/glue-datasyncer/context"
	"gluenet/pkg/apis"
	"net/http"
	"regexp"
	"sync"
)

func SocketList(c *streamCtx.StreamContext) {
	var metrics []map[string]string
	c.MetricLabels.Range(func(key, value interface{}) bool {
		metrics = append(metrics, value.(map[string]string))
		return true
	})
	c.WebContext.JSON(apis.ResponseOK(metrics))
}

func Socket(c *streamCtx.StreamContext) {
	params := c.WebContext.URLParams()
	c.Logger.Debugf("metrics socket %v", params)

	var matchKeys []string
	c.MetricLabels.Range(func(key, value interface{}) bool {
		labels := value.(map[string]string)
		allMatch := true
		for lname, lvalue := range labels {
			pvalue, ok := params[lname]
			if !ok {
				continue
			}
			match, err := regexp.MatchString(pvalue, lvalue)
			if err != nil {
				allMatch = false
				break
			}
			if !match {
				allMatch = false
				break
			}
		}
		if allMatch {
			matchKeys = append(matchKeys, key.(string))
		}
		return true
	})

	if len(matchKeys) == 0 {
		c.Logger.Debugf("match keys less than 0")
		return
	}

	c.Logger.Debugf("match keys %v", matchKeys)

	ctx, cancel := context.WithCancel(c.Context)
	var ActuallyNodeCpu = websocket.New(gorilla.Upgrader(gorillaWs.Upgrader{
		CheckOrigin: func(*http.Request) bool { return true },
	}), websocket.Events{
		websocket.OnNativeMessage: func(conn *neffos.NSConn, message neffos.Message) error { return nil },
	})

	ActuallyNodeCpu.OnConnect = func(n *websocket.Conn) error {
		for _, key := range matchKeys {
			c.Logger.Debugf("OnConnect from server %v %v", n.ID(), key)
			subi, ok := c.MetricSubChan.Load(key)
			if !ok {
				c.Logger.Errorf("metrics not found")
				return nil
			}

			sub := subi.(*sync.Map)
			rchi, _ := sub.LoadOrStore(n.ID(), make(chan string))
			rch := rchi.(chan string)

			go func() {
				for {
					select {
					case data := <-rch:
						n.Write(neffos.Message{
							Body:     []byte(data),
							IsNative: true,
						})
					case <-ctx.Done():
						sub.Delete(n.ID())
						close(rch)
						//c.Logger.Debugf("push down %v", n.ID())
						return
					}
				}
			}()
		}
		<-ctx.Done()
		return nil
	}

	ActuallyNodeCpu.OnDisconnect = func(n *websocket.Conn) {
		cancel()
		c.Logger.Debugf("Disconnected from server", n.ID())
	}

	ActuallyNodeCpu.OnUpgradeError = func(err error) {
		cancel()
		c.Logger.Debugf("OnUpgradeError from server %v", err)
	}

	websocket.Handler(ActuallyNodeCpu)(c.WebContext)
}
